﻿using System;
using System.Collections.Generic;
using System.Linq;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Linq;

namespace NHibData.Repository
{
    /// <summary>
    /// Realization of interface BaseRepository
    /// </summary>
    internal class NHibernateRepository<T> : IRepository<T> where T: BaseEntity
    {
        #region IBaseRepository<T> Members


        /// <summary>
        /// The name of the config file 
        /// By dufault - using dufault name, but it could be redefined if it's needed to use concrete repository with another DB
        /// </summary>
        protected readonly string _nHibernareConfigName;


        /// <summary>
        /// Default constructor
        /// </summary>
        public NHibernateRepository()
        {
            _nHibernareConfigName = NHibernateHelper.DefaultNHibernateConfigName;  
        }

        /// <summary>
        /// Constructor with parameter. For using with another DBs
        /// </summary>
        /// <param name="nHibernareConfigName">name of the config file</param>
        public NHibernateRepository(string nHibernareConfigName)
        {
            _nHibernareConfigName = nHibernareConfigName;
        }
        
        /// <summary>
        /// Find domain object by ID
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual T FindById(int id)
        {
            ISession session = NHibernateHelper.GetCurrentSession(_nHibernareConfigName);
            return session.Get<T>(id);            
        }

        /// <summary>
        /// Returns all objects of given type
        /// </summary>
        /// <returns></returns>
        public virtual IList<T> FindAll()
        {
            ISession session = NHibernateHelper.GetCurrentSession(_nHibernareConfigName);
            ICriteria cr = session.CreateCriteria(typeof(T));
            return cr.List<T>();
        }

        /// <summary>
        /// Saves new domain object to DB
        /// </summary>
        /// <param name="t">domain object</param>
        public virtual void SaveNew(T t)
        {
            if(t == null)
                throw new NullReferenceException("repository.save(domainObject)");

            ISession session = NHibernateHelper.GetCurrentSession(_nHibernareConfigName);
            session.Save(t);                        
        }

       
        /// <summary>
        /// Update domain object
        /// </summary>
        /// <param name="t">domain obj</param>
        public virtual void Update(T t)
        {
            if (t == null)
                throw new NullReferenceException("repository.update(domainObject)");

            ISession session = NHibernateHelper.GetCurrentSession(_nHibernareConfigName);
            session.Update(t);            
        }

        /// <summary>
        /// Invoke SaveNew or Update methods depending on if object is new or not
        /// </summary>
        /// <param name="t">domain obj</param>
        public virtual void SaveOrUpdate(T t)
        {
            ISession session = NHibernateHelper.GetCurrentSession(_nHibernareConfigName);
            session.SaveOrUpdate(t); 
        }

        /// <summary>
        /// Delete domain object
        /// </summary>
        /// <param name="t">domain obj</param>
        public virtual void Delete(T t)
        {
            if (t == null)
                throw new NullReferenceException("repository.save(domainObject)");

            ISession session = NHibernateHelper.GetCurrentSession(_nHibernareConfigName);
            session.Delete(t);            
        }

        public IQueryable<T> Linq
        {
            get
            {
                return NHibernateHelper.GetCurrentSession(_nHibernareConfigName).Query<T>();
            }
        }

        #endregion

        /// <summary>
        /// Returns all data in compliance with given criteria
        /// </summary>
        /// <param name="criteria">Criteria</param>
        /// <returns>results</returns>
        public IList<T> FindAll(DetachedCriteria criteria)
        {
            ISession session = NHibernateHelper.GetCurrentSession(_nHibernareConfigName);
            return criteria.GetExecutableCriteria(session).List<T>();
        }
    }
}